package org.bulkLoader.comply
{
	import flash.events.EventDispatcher;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.Dictionary;
	
	import org.bulkLoader.events.BulkEvent;
	import org.bulkLoader.events.BulkItemLoadingEvent;
	import org.bulkLoader.handler.BulkHandler;
	import org.bulkLoader.loadinginfo.BulkItemLoadingInfo;
	import org.bulkLoader.loadinginfo.BulkListLoadingInfo;
	import org.bulkLoader.loadinginfo.IBulkItemLoadingInfo;
	import org.bulkLoader.loadinginfo.IBulkListLoadingInfo;

	/*Event Types*/
	[Event(name="itemStart", type="org.bulkLoader.events.BulkEvent")]
	[Event(name="itemProgress", type="org.bulkLoader.events.BulkEvent")]
	[Event(name="itemComplete", type="org.bulkLoader.events.BulkEvent")]
	[Event(name="itemError", type="org.bulkLoader.events.BulkEvent")]
	[Event(name="bulkStart", type="org.bulkLoader.events.BulkEvent")]
	[Event(name="bulkProgress", type="org.bulkLoader.events.BulkEvent")]
	[Event(name="bulkComplete", type="org.bulkLoader.events.BulkEvent")]
	
	public class BulkLoader extends EventDispatcher
	{
		private var _name:String;
		private var _numConnection:uint;
		private var _loaderContext:LoaderContext;
		
		public function BulkLoader(name:String,
								   numConnections:uint = BulkLoaderDefine.DEFAULT_NUM_CONNECTIONS, 
								   loaderContext:LoaderContext = null)
		{
			_name = name;
			_numConnection = numConnections;
			_loaderContext = loaderContext ? loaderContext:BulkLoaderDefine.defaultLoaderContext;
			
			BulkLoaderDefine.registerInstance(_name, this);
		}
		
		private var _currLoadList:Vector.<IBulkFile> = null;
		private var _inLoading:Boolean = false;
		
		private var _loadedProcessIn:uint = 0; /*文件池加载进度*/
		private var _loadFileLinePool:Vector.<IBulkFile> = new Vector.<IBulkFile>(); /*文件线*/
		private var _loadingInfo:BulkListLoadingInfo = new BulkListLoadingInfo(); // 本次加载信息 as percentage, as tutalBytes...
		private var _loading:Vector.<int> = new Vector.<int>(); /*正在加载的文件*/
		
//		private var _fileTypeToHandlerCls:Dictionary; /*BulkFileType-BulkHandler Class Type*/
		private var _fileToHandlerInstance:Dictionary = new Dictionary(true); /*BulkFile-BulkHandler*/
		private var _fileToList:Dictionary = new Dictionary(true); /*BulkFile-BulkList*/
		private var _fileToitem:Dictionary = new Dictionary(true); /*BulkFile-BulkListItem*/
		private var _itemToFile:Dictionary = new Dictionary(true); /*BulkListItem-BulkFile*/
		private var _fileToLoadingInfo:Dictionary = new Dictionary(true); /*BulkFile-BulkItemLoadingInfo*/
		private var _listToLoadingInfo:Dictionary = new Dictionary(true); /*BulkList-BulkListLoadingInfo*/
		
		
		private function buildFile(url:String, parameter:Object):IBulkFile
		{
			var file:BulkFile = new BulkFile(url, parameter);
			var fileLoadingInfo:BulkItemLoadingInfo = new BulkItemLoadingInfo();
			
			_fileToLoadingInfo[file] = fileLoadingInfo;
			
			return file;
		}
		
		private function activeLoader():void
		{
			while (_loadFileLinePool.length > _loadedProcessIn)/*文件池有文件加载*/
			{
				if (_loading.length >= _numConnection) /*加载达到最大并发量*/
					break;
					
				var file:IBulkFile = _loadFileLinePool[_loadedProcessIn];
				gotoLoadFile(file);
				
				_loading.push(file); /*更新计数器*/
				_loadedProcessIn ++;
			}
		}
		
		private function gotoLoadFile(file:IBulkFile):void
		{
			var handlerCls:Class = BulkLoaderDefine.getHandlerCLass(file.type);
			if (!handlerCls) /*找不到该文件类型的加载处理程序*/
			{
//				handlerCls = _fileTypeToHandlerCls[BulkLoaderDefine.FILE_BINARY];
				// or to new error,,
				new Error("you load fileType("+file.type+") of BulkLoader is not support.");
			}
			
			var loadHandler:BulkHandler = new handlerCls(file, _fileToLoadingInfo[file], _loaderContext);
			loadHandler.addEventListener(BulkItemLoadingEvent.ITEM_START, onItemStart);
			loadHandler.addEventListener(BulkItemLoadingEvent.ITEM_PROGRESS, onItemProgress);
			loadHandler.addEventListener(BulkItemLoadingEvent.ITEM_COMPLETED, onItemComplete);
			loadHandler.addEventListener(BulkItemLoadingEvent.ITEM_ERROR, onItemError);
			_fileToHandlerInstance[loadHandler] = loadHandler;
			loadHandler.load();
		}
		
		/////////////////////////////////////////////////////////////////////////////////////////////
		protected function onItemError(event:BulkItemLoadingEvent):void
		{
			var file:IBulkFile = event.file;
			
			/*更新计数*/
			var index:int = _loading.indexOf(file);
			if (index != -1)
			{
				_loading.splice(index, 1);
				activeLoader();
			}
			
			/*throw event*/
			if (isFirstFileOfList(file))
				throwListStart(file);
			
			var itemErrorEvent:BulkEvent = new BulkEvent(BulkEvent.ITEM_ERROR);
			itemErrorEvent.file = file;
			itemErrorEvent.fileLoadingInfo = event.loadingInfo;
			itemErrorEvent.bulkLoadingInfo = calculateListLoaderInfo();
			dispatchEvent(itemErrorEvent);
			
			if (isEndFileOfList(file))
				throwListComplete(file);
		}
		
		private function throwListComplete(file:IBulkFile):void
		{
			var listCompleteEvent:BulkEvent = new BulkEvent(BulkEvent.BULK_COMPLETED);
			listCompleteEvent.file = file;
			listCompleteEvent.fileLoadingInfo = _fileToLoadingInfo[file];
			listCompleteEvent.bulkLoadingInfo = calculateListLoaderInfo();
			dispatchEvent(listCompleteEvent);
		}
		
		private function throwListStart(file:IBulkFile):void
		{
			var listStartEvent:BulkEvent = new BulkEvent(BulkEvent.BULK_START);
			listStartEvent.file = file;
			listStartEvent.fileLoadingInfo = _fileToLoadingInfo[file];
			listStartEvent.bulkLoadingInfo = calculateListLoaderInfo();
			dispatchEvent(listStartEvent);
		}
		
		protected function onItemComplete(event:BulkItemLoadingEvent):void
		{
			var file:IBulkFile = event.file;
			
			/*更新计数*/
			var index:int = _loading.indexOf(file);
			if (index != -1)
			{
				_loading.splice(index, 1);
				activeLoader();
			}
			
			/*throw event*/
			var itemCompleteEvent:BulkEvent = new BulkEvent(BulkEvent.ITEM_COMPLETED);
			itemCompleteEvent.file = file;
			itemCompleteEvent.fileLoadingInfo = event.loadingInfo;
			itemCompleteEvent.bulkLoadingInfo = calculateListLoaderInfo();
			dispatchEvent(itemCompleteEvent);
			
			if (isEndFileOfList(file))
				throwListComplete(file);
		}
		
		protected function onItemStart(event:BulkItemLoadingEvent):void
		{
			var file:IBulkFile = event.file;
			
			/*throw event*/
			if (isFirstFileOfList(file))
				throwListStart(file);
			
			var itemStartEvent:BulkEvent = new BulkEvent(BulkEvent.ITEM_START);
			itemStartEvent.file = file;
			itemStartEvent.fileLoadingInfo = event.loadingInfo;
			itemStartEvent.bulkLoadingInfo = calculateListLoaderInfo();
			dispatchEvent(itemStartEvent);
		}
		
		protected function onItemProgress(event:BulkItemLoadingEvent):void
		{
			var file:IBulkFile = event.file;
			
			var itemProgressEvent:BulkEvent = new BulkEvent(BulkEvent.BULK_PROGRESS);
			var listProgressEvent:BulkEvent = new BulkEvent(BulkEvent.BULK_PROGRESS);
			itemProgressEvent.file = listProgressEvent.file = file;
			itemProgressEvent.fileLoadingInfo = listProgressEvent.fileLoadingInfo = event.loadingInfo;
			itemProgressEvent.bulkLoadingInfo = listProgressEvent.bulkLoadingInfo = calculateListLoaderInfo();
			dispatchEvent(itemProgressEvent);
			dispatchEvent(listProgressEvent);
		}
		
		/**
		 * 计算更新当前列表的加载信息 as tutal, as percentage
		 * @return 
		 * 
		 */		
		private function calculateListLoaderInfo():IBulkListLoadingInfo
		{
			_loadingInfo.bytesTotal = 0;
			_loadingInfo.bytesLoaded = 0;
			_loadingInfo.percentage = 0;
			
			var listItemsInLoadingCount:uint = 0;
			var currListLen:uint = _currLoadList.length;
			for (var i:int=0; i<currListLen; i++)
			{
				var file:IBulkFile = _currLoadList[i];
				var fileLoadingInfo:IBulkItemLoadingInfo = _fileToLoadingInfo[file];
				
				_loadingInfo.bytesTotal += fileLoadingInfo.getBytesTotal();
				_loadingInfo.bytesLoaded += fileLoadingInfo.getBytesLoaded();
				
				if (fileLoadingInfo.getBytesTotal() > 0 && fileLoadingInfo.getBytesLoaded() > 0)
					listItemsInLoadingCount ++;
				
				var percentage:Number = fileLoadingInfo.getPercentage();
				if (!isNaN(percentage))
					_loadingInfo.percentage += percentage/currListLen;
			}
			
			return _loadingInfo;
		}
		
		/**
		 * 判断file是否为本次加载列表第一个
		 * @param file
		 * @return 
		 * 
		 */		
		protected function isFirstFileOfList(file:IBulkFile):Boolean
		{
			return (
				_currLoadList.length > 0 && 
				_loadFileLinePool[0] == file
			);
		}
		
		/**
		 * 判断file是否为本次加载列表最后一个
		 * @param file
		 * @return 
		 * 
		 */		
		protected function isEndFileOfList(file:IBulkFile):Boolean
		{
			var l:uint = _loadFileLinePool.length;
			return (
				l > 0 && 
				_loadFileLinePool[l-1] == file
			);
		}
		
		/**
		 * 
		 * @return 系统加载线中未加载的文件
		 * 
		 */		
		public function getUnLoadFles():Vector.<IBulkFile>
		{
			return null;
		}
		
		public function add(url:String, parameter:Object):void
		{
			if (_inLoading)
			{
				return ;
			}
			
			// build BulkFile
			var file:IBulkFile = buildFile(url, parameter);
			_loadFileLinePool.push(file);
		}
		
		public function execute():void
		{
			if (_inLoading)
			{
				return;
			}
			
			_currLoadList = _loadFileLinePool.slice(_loadedProcessIn, _loadFileLinePool.length);
			_inLoading = true;
			
			activeLoader();
		}
		
		public function getDataByTitle(title:*):*
		{
			var files:Vector.<IBulkFile> = _loadFileLinePool.concat();
			while (files.length) 
			{
				var file:IBulkFile = files.pop();
				var fileTitle:* = file.ownParameter.hasOwnProperty(BulkLoaderDefine.ITEM_TITLE) ? 
					file.ownParameter[BulkLoaderDefine.ITEM_TITLE]:null;
				
				if (fileTitle != null && fileTitle == title) 
					return (_fileToLoadingInfo[file] as BulkItemLoadingInfo).data;
			}
			return null;
		}
	}
}